﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CodeC.Interfaces;
using CodeC.Models;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Diagnostics;
using System.ComponentModel.Composition;
using System.Reflection;
using System.IO;

namespace CodeC.Utilities
{
    //This line is return for supress the warning message from 'cSharpCodeProvider.CreateCompiler();'
#pragma warning disable

    /// <summary>
    /// This class is compile the console appliation code and return results
    /// </summary>
    [Export(typeof(ICodeCEngine))]
    public class CodeCEngine : ICodeCEngine
    {

        public IOutputModel<string> CompileCode(string code, List<string> listOfReferences)
        {
            IOutputModel<string> outputModel;
            CSharpCodeProvider cSharpCodeProvider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
            ICodeCompiler codeCompiler = cSharpCodeProvider.CreateCompiler();
            string exeFileName = ExeFileName;

            #region Compile & Output
            string str = AppDomain.CurrentDomain.BaseDirectory;
            CompilerParameters parameters = new CompilerParameters();


            #region Adding References
            if (null != listOfReferences)
                foreach (var item in listOfReferences)
                {
                    parameters.ReferencedAssemblies.Add((item));
                }
            #endregion


            parameters.GenerateExecutable = true;
            parameters.GenerateInMemory = false;
            parameters.OutputAssembly = exeFileName;
            parameters.TreatWarningsAsErrors = false;
            CompilerResults results = codeCompiler.CompileAssemblyFromSource(parameters, code);
            if (results.Errors.Count > 0)
                outputModel = new OutputModel<string> { Errors = results.Errors };
            else
                outputModel = new OutputModel<string> { Result = GetOutput(exeFileName) };

            #endregion

            return outputModel;
        }

        /// <summary>
        /// This property gives the default console file name.
        /// </summary>
        private string _exeFileName;
        private string ExeFileName
        {
            get
            {
                if (null == _exeFileName)
                    _exeFileName = string.Format("CodeC_{0}.exe", "21052010");
                return _exeFileName;
            }
        }

        /// <summary>
        /// This method collect the console output and returns to string
        /// </summary>
        /// <param name="exeName"></param>
        /// <returns></returns>
        private string GetOutput(string exeName)
        {
            string result;
            Process compiler = new Process();
            compiler.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
            compiler.StartInfo.FileName = exeName;
            compiler.StartInfo.RedirectStandardOutput = true;
            compiler.StartInfo.UseShellExecute = false;
            compiler.StartInfo.CreateNoWindow = true;
            compiler.Start();

            result = compiler.StandardOutput.ReadToEnd();
            compiler.WaitForExit();

            return result;
        }

    }
}
